﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace KP_CommonLibrary.KP_CommonControls.NumericInput
{
   public class NumericMaskManager : MaskManagerStated
{
    // Fields
    protected readonly bool AllowNull;
    private TypeCode? editValueTypeCode;
    private NumericFormatter[] formatters;
    private NumericMaskLogic logic;
    private readonly string negativeSignString;

    // Methods
    [Obsolete("Use NumericMaskManager(string formatString, CultureInfo managerCultureInfo, bool allowNull) instead")]
    public NumericMaskManager(string formatString, CultureInfo managerCultureInfo) : this(formatString, managerCultureInfo, false)
    {
    }

    public NumericMaskManager(string formatString, CultureInfo managerCultureInfo, bool allowNull) : base(NumericMaskManagerState.NullInstance)
    {
        this.formatters = new NumericFormatter[2];
        this.AllowNull = allowNull;
        formatString = NumericFormatter.Expand(formatString, managerCultureInfo);
        this.negativeSignString = managerCultureInfo.NumberFormat.NegativeSign;
        int index = formatString.Replace(@"\\", "//").Replace(@"\;", "/:").IndexOf(';');
        if (index < 0)
        {
            this.formatters[0] = new NumericFormatter(formatString, managerCultureInfo);
            this.formatters[1] = null;
        }
        else
        {
            this.formatters[0] = new NumericFormatter(formatString.Substring(0, index), managerCultureInfo);
            this.formatters[1] = new NumericFormatter(formatString.Substring(index + 1), managerCultureInfo);
            if (this.formatters[0].MaxDigitsBeforeDecimalSeparator != this.formatters[1].MaxDigitsBeforeDecimalSeparator)
            {
                throw new ArgumentException("Incorrect mask: the max number of digits before the decimal separator in the positive and negative patterns must match");
            }
            if (this.formatters[0].MaxDigitsAfterDecimalSeparator != this.formatters[1].MaxDigitsAfterDecimalSeparator)
            {
                throw new ArgumentException("Incorrect mask: the max number of digits after the decimal separator in the positive and negative patterns must match");
            }
            if (this.formatters[0].MinDigitsBeforeDecimalSeparator != this.formatters[1].MinDigitsBeforeDecimalSeparator)
            {
                throw new ArgumentException("Incorrect mask: the min number of digits before the decimal separator in the positive and negative patterns must match");
            }
            if (this.formatters[0].MinDigitsAfterDecimalSeparator != this.formatters[1].MinDigitsAfterDecimalSeparator)
            {
                throw new ArgumentException("Incorrect mask: the min number of digits after the decimal separator in the positive and negative patterns must match");
            }
            if (this.formatters[0].Is100Multiplied != this.formatters[1].Is100Multiplied)
            {
                throw new ArgumentException("Incorrect mask: the percent type (% or %%) in the positive and negative patterns must match");
            }
        }
        this.logic = new NumericMaskLogic(this.formatters[0].MaxDigitsBeforeDecimalSeparator, this.formatters[0].MinDigitsBeforeDecimalSeparator, this.formatters[0].MinDigitsAfterDecimalSeparator, this.formatters[0].MaxDigitsAfterDecimalSeparator, managerCultureInfo);
        if ((this.formatters[0].MaxDigitsAfterDecimalSeparator > 0) || this.formatters[0].Is100Multiplied)
        {
            this.editValueTypeCode = (TypeCode)15;
        }
    }

    public override bool Backspace()
    {
        MaskLogicResult result;
        if (this.CurrentState.IsNull)
        {
            return false;
        }
        if (base.IsSelection)
        {
            if (this.AllowNull)
            {
                int num = Math.Min(this.CurrentState.SelectionAnchor, this.CurrentState.CursorPosition);
                int num2 = Math.Max(this.CurrentState.SelectionAnchor, this.CurrentState.CursorPosition);
                if ((num == 0) && (num2 == this.CurrentState.EditText.Length))
                {
                    return base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Delete);
                }
            }
            return this.Insert(string.Empty);
        }
        if (this.CurrentState.CursorPosition <= 0)
        {
            result = this.logic.GetEditResult(string.Empty, string.Empty, this.CurrentState.EditText, string.Empty);
        }
        else
        {
            result = this.logic.GetEditResult(this.CurrentState.EditText.Substring(0, this.CurrentState.CursorPosition - 1), this.CurrentState.EditText.Substring(this.CurrentState.CursorPosition - 1, 1), this.CurrentState.EditText.Substring(this.CurrentState.CursorPosition), string.Empty);
        }
        if (result == null)
        {
            return base.CursorLeft(false);
        }
        if (base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, this.CurrentState.IsNegative), MaskManagerStated.StateChangeType.Delete))
        {
            return true;
        }
        if (this.CurrentState.IsNegative)
        {
            return base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, false), MaskManagerStated.StateChangeType.Delete);
        }
        return ((this.AllowNull && !IsSomethingExceptDotsAndZeros(result.EditText)) && base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Delete));
    }

    public override void ClearAfterSelectAll()
    {
        if (this.AllowNull)
        {
            base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Delete);
        }
        else
        {
            MaskLogicResult result = this.logic.GetEditResult(string.Empty, this.CurrentState.EditText, string.Empty, string.Empty);
            base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, false), MaskManagerStated.StateChangeType.Delete);
        }
    }

    public override bool CursorEnd(bool forceSelection)
    {
        return this.StateCursorPositionTo(this.CurrentState.EditText.Length, forceSelection);
    }

    public override bool CursorHome(bool forceSelection)
    {
        return this.StateCursorPositionTo(0, forceSelection);
    }

    public override bool CursorLeft(bool forceSelection, bool isNeededKeyCheck)
    {
        return this.StateCursorPositionTo(this.CurrentState.CursorPosition - 1, forceSelection, isNeededKeyCheck);
    }

    public override bool CursorRight(bool forceSelection, bool isNeededKeyCheck)
    {
        return this.StateCursorPositionTo(this.CurrentState.CursorPosition + 1, forceSelection, isNeededKeyCheck);
    }

    public override bool CursorToDisplayPosition(int newPosition, bool forceSelection)
    {
        return this.StateCursorPositionTo(this.GetFormatter(this.CurrentState).GetPositionSource(this.CurrentState.EditText, newPosition), forceSelection);
    }

    public override bool Delete()
    {
        MaskLogicResult result;
        if (this.CurrentState.IsNull)
        {
            return false;
        }
        if (base.IsSelection)
        {
            if (this.AllowNull)
            {
                int num = Math.Min(this.CurrentState.SelectionAnchor, this.CurrentState.CursorPosition);
                int num2 = Math.Max(this.CurrentState.SelectionAnchor, this.CurrentState.CursorPosition);
                if ((num == 0) && (num2 == this.CurrentState.EditText.Length))
                {
                    return base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Delete);
                }
            }
            return this.Insert(string.Empty);
        }
        if (this.CurrentState.CursorPosition >= this.CurrentState.EditText.Length)
        {
            result = this.logic.GetEditResult(this.CurrentState.EditText, string.Empty, string.Empty, string.Empty);
        }
        else
        {
            result = this.logic.GetEditResult(this.CurrentState.EditText.Substring(0, this.CurrentState.CursorPosition), this.CurrentState.EditText.Substring(this.CurrentState.CursorPosition, 1), this.CurrentState.EditText.Substring(this.CurrentState.CursorPosition + 1), string.Empty);
        }
        if (result == null)
        {
            return base.CursorRight(false);
        }
        if (base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, this.CurrentState.IsNegative), MaskManagerStated.StateChangeType.Delete))
        {
            return true;
        }
        if (this.CurrentState.IsNegative)
        {
            return base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, false), MaskManagerStated.StateChangeType.Delete);
        }
        return ((this.AllowNull && !IsSomethingExceptDotsAndZeros(result.EditText)) && base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Delete));
    }

    private bool ForceEditValueTypeCode(TypeCode forcedCode)
    {
        switch (forcedCode)
        {
            case TypeCode.SByte:
            case TypeCode.Byte:
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
            case TypeCode.Int64:
            case TypeCode.UInt64:
            case TypeCode.Single:
            case TypeCode.Double:
            case TypeCode.Decimal:
                this.editValueTypeCode = new TypeCode?(forcedCode);
                return true;
        }
        this.editValueTypeCode = (TypeCode)0x12;
        return true;
    }

    protected override int GetCursorPosition(MaskManagerState state)
    {
        NumericMaskManagerState state2 = (NumericMaskManagerState) state;
        if (state2.IsNull)
        {
            return 0;
        }
        return this.GetFormatter(state2).GetPositionFormatted(state2.EditText, state2.CursorPosition);
    }

    protected override string GetDisplayText(MaskManagerState state)
    {
        NumericMaskManagerState state2 = (NumericMaskManagerState) state;
        if (state2.IsNull)
        {
            return string.Empty;
        }
        return this.GetFormatter(state2).Format(state2.EditText);
    }

    protected override string GetEditText(MaskManagerState state)
    {
        NumericMaskManagerState state2 = (NumericMaskManagerState) state;
        if (state2.IsNegative)
        {
            return ('-' + state2.EditText);
        }
        return state2.EditText;
    }

    protected override object GetEditValue(MaskManagerState state)
    {
        if (((NumericMaskManagerState) state).IsNull)
        {
            return null;
        }
        string editText = this.GetEditText(state);
        if (this.formatters[0].Is100Multiplied)
        {
            editText = NumericMaskLogic.Div100(editText);
        }
        if (editText.IndexOf('.') >= 0)
        {
            while (editText.EndsWith("0"))
            {
                editText = editText.Substring(0, editText.Length - 1);
            }
        }
        if (editText.EndsWith("."))
        {
            editText = editText.Substring(0, editText.Length - 1);
        }
        if ((editText.Length == 0) || (editText == "-"))
        {
            editText = editText + '0';
        }
        if (this.editValueTypeCode.HasValue)
        {
            try
            {
                return Convert.ChangeType(editText, this.editValueTypeCode.Value, CultureInfo.InvariantCulture);
            }
            catch
            {
                goto Label_00E6;
            }
        }
        try
        {
            return Convert.ChangeType(editText, TypeCode.Int32, CultureInfo.InvariantCulture);
        }
        catch
        {
        }
        try
        {
            return Convert.ChangeType(editText, TypeCode.Decimal, CultureInfo.InvariantCulture);
        }
        catch
        {
        }
    Label_00E6:
        return null;
    }

    private NumericFormatter GetFormatter(NumericMaskManagerState state)
    {
        return this.formatters[state.IsNegative ? 1 : 0];
    }

    protected override int GetSelectionAnchor(MaskManagerState state)
    {
        NumericMaskManagerState state2 = (NumericMaskManagerState) state;
        if (state2.IsNull)
        {
            return 0;
        }
        return this.GetFormatter(state2).GetPositionFormatted(state2.EditText, state2.SelectionAnchor);
    }

    public override bool Insert(string insertion)
    {
        if (this.IsSignedMask && ((insertion == "-") || (insertion == this.negativeSignString)))
        {
            if (!this.CurrentState.IsNull)
            {
                return base.Apply(new NumericMaskManagerState(this.CurrentState.EditText, this.CurrentState.CursorPosition, this.CurrentState.SelectionAnchor, !this.CurrentState.IsNegative), MaskManagerStated.StateChangeType.Insert);
            }
            MaskLogicResult result = this.logic.GetEditResult(string.Empty, string.Empty, string.Empty, string.Empty);
            if (result == null)
            {
                return false;
            }
            return base.Apply(new NumericMaskManagerState(result.EditText, 0, result.EditText.Length, true), MaskManagerStated.StateChangeType.Insert);
        }
        int length = (this.CurrentState.CursorPosition < this.CurrentState.SelectionAnchor) ? this.CurrentState.CursorPosition : this.CurrentState.SelectionAnchor;
        int startIndex = (this.CurrentState.CursorPosition < this.CurrentState.SelectionAnchor) ? this.CurrentState.SelectionAnchor : this.CurrentState.CursorPosition;
        MaskLogicResult result2 = this.logic.GetEditResult(this.CurrentState.EditText.Substring(0, length), this.CurrentState.EditText.Substring(length, startIndex - length), this.CurrentState.EditText.Substring(startIndex), insertion);
        if (result2 == null)
        {
            return false;
        }
        bool isNegative = this.CurrentState.IsNegative;
        if (this.IsSignedMask && ((insertion.IndexOf("-") >= 0) || (insertion.IndexOf(this.negativeSignString) >= 0)))
        {
            isNegative = !isNegative;
        }
        return base.Apply(new NumericMaskManagerState(result2.EditText, result2.CursorPosition, result2.CursorPosition, isNegative), MaskManagerStated.StateChangeType.Insert);
    }

    private static bool IsSomethingExceptDotsAndZeros(string input)
    {
        for (int i = 0; i < input.Length; i++)
        {
            char ch = input[i];
            if ((ch != '0') && (ch != '.'))
            {
                return true;
            }
        }
        return false;
    }

    protected override bool IsValid(MaskManagerState newState)
    {
        NumericMaskManagerState state = newState as NumericMaskManagerState;
        if (state == null)
        {
            return false;
        }
        if (!state.IsNull && (this.GetEditValue(state) == null))
        {
            return false;
        }
        return true;
    }

    private bool IsValidInvariantCultureDecimal(string testedString)
    {
        int index = testedString.IndexOf('.');
        for (int i = 0; i < testedString.Length; i++)
        {
            if (i != index)
            {
                char ch = testedString[i];
                if ((ch < '0') || (ch > '9'))
                {
                    return false;
                }
            }
        }
        return true;
    }

    public override void PrepareForInsertAfterSelectAll()
    {
        if (this.AllowNull || this.CurrentState.IsNull)
        {
            base.Apply(NumericMaskManagerState.NullInstance, MaskManagerStated.StateChangeType.Insert);
        }
        else
        {
            base.Apply(new NumericMaskManagerState(this.CurrentState.EditText, this.CurrentState.EditText.Length, 0, false), MaskManagerStated.StateChangeType.Insert);
        }
    }

    public override void SetInitialEditText(string initialEditText)
    {
        if (initialEditText == null)
        {
            initialEditText = string.Empty;
        }
        if (this.AllowNull && string.IsNullOrEmpty(initialEditText))
        {
            base.SetInitialState(NumericMaskManagerState.NullInstance);
        }
        else
        {
            MaskLogicResult result;
            string testedString = initialEditText.Trim();
            bool isNegative = false;
            if (testedString.StartsWith("-"))
            {
                testedString = testedString.Substring(1);
                if (this.IsSignedMask)
                {
                    isNegative = true;
                }
            }
            if (this.IsValidInvariantCultureDecimal(testedString))
            {
                result = this.logic.GetEditResult(testedString, string.Empty, string.Empty, string.Empty);
                if (result != null)
                {
                    result = this.logic.GetEditResult(string.Empty, string.Empty, result.EditText, string.Empty);
                }
            }
            else
            {
                result = this.logic.GetEditResult(string.Empty, string.Empty, string.Empty, initialEditText);
            }
            if (result == null)
            {
                result = this.logic.GetEditResult(string.Empty, string.Empty, string.Empty, string.Empty);
            }
            int index = result.EditText.IndexOf('.');
            if (index < 0)
            {
                index = result.EditText.Length;
            }
            base.SetInitialState(new NumericMaskManagerState(result.EditText, index, index, isNegative));
        }
    }

    public override void SetInitialEditValue(object initialEditValue)
    {
        if (initialEditValue == null)
        {
            this.SetInitialEditText(null);
        }
        else
        {
            this.ForceEditValueTypeCode(Type.GetTypeCode(initialEditValue.GetType()));
            int maxDigitsAfterDecimalSeparator = this.formatters[0].MaxDigitsAfterDecimalSeparator;
            if (this.formatters[0].Is100Multiplied)
            {
                maxDigitsAfterDecimalSeparator += 2;
            }
            string format = "{0:f" + maxDigitsAfterDecimalSeparator.ToString(CultureInfo.InvariantCulture) + "}";
            string input = string.Format(CultureInfo.InvariantCulture, format, new object[] { initialEditValue });
            if (this.formatters[0].Is100Multiplied)
            {
                input = NumericMaskLogic.Mul100(input);
            }
            this.SetInitialEditText(input);
        }
    }

    public override bool SpinDown()
    {
        return this.SpinKeys(false);
    }

    private bool SpinKeys(bool isUp)
    {
        bool flag;
        int cursorPosition = this.CurrentState.CursorPosition;
        if (this.CurrentState.SelectionAnchor != this.CurrentState.CursorPosition)
        {
            int startIndex = (this.CurrentState.SelectionAnchor < this.CurrentState.CursorPosition) ? this.CurrentState.SelectionAnchor : this.CurrentState.CursorPosition;
            int num3 = (this.CurrentState.SelectionAnchor < this.CurrentState.CursorPosition) ? this.CurrentState.CursorPosition : this.CurrentState.SelectionAnchor;
            if (((startIndex == 0) && (num3 == this.CurrentState.EditText.Length)) || (this.CurrentState.EditText.Substring(startIndex, num3 - startIndex).IndexOf('.') >= 0))
            {
                cursorPosition = this.CurrentState.EditText.IndexOf('.');
                if (cursorPosition < 0)
                {
                    cursorPosition = this.CurrentState.EditText.Length;
                }
            }
            else
            {
                cursorPosition = num3;
            }
        }
        bool isModuloDecrement = isUp ? this.CurrentState.IsNegative : !this.CurrentState.IsNegative;
        MaskLogicResult result = this.logic.GetSpinResult(this.CurrentState.EditText.Substring(0, cursorPosition), this.CurrentState.EditText.Substring(cursorPosition), isModuloDecrement, this.IsSignedMask, out flag);
        if (result == null)
        {
            return false;
        }
        bool isNegative = flag ? !this.CurrentState.IsNegative : this.CurrentState.IsNegative;
        return base.Apply(new NumericMaskManagerState(result.EditText, result.CursorPosition, result.CursorPosition, isNegative), MaskManagerStated.StateChangeType.Insert);
    }

    public override bool SpinUp()
    {
        return this.SpinKeys(true);
    }

    private bool StateCursorPositionTo(int newPosition, bool forceSelection)
    {
        return this.StateCursorPositionTo(newPosition, forceSelection, false);
    }

    private bool StateCursorPositionTo(int newPosition, bool forceSelection, bool isNeededKeyCheck)
    {
        if (this.CurrentState.IsNull)
        {
            return false;
        }
        if (newPosition < 0)
        {
            newPosition = 0;
        }
        else if (newPosition > this.CurrentState.EditText.Length)
        {
            newPosition = this.CurrentState.EditText.Length;
        }
        return base.Apply(new NumericMaskManagerState(this.CurrentState.EditText, newPosition, forceSelection ? this.CurrentState.SelectionAnchor : newPosition, this.CurrentState.IsNegative), MaskManagerStated.StateChangeType.Terminator, isNeededKeyCheck);
    }

    // Properties
    protected new NumericMaskManagerState CurrentState
    {
        get
        {
            return (NumericMaskManagerState) base.CurrentState;
        }
    }

    public override bool IsEditValueDifferFromEditText
    {
        get
        {
            return true;
        }
    }

    public override bool IsFinal
    {
        get
        {
            if (this.CurrentState.IsNull)
            {
                return false;
            }
            if (this.CurrentState.EditText.Length != this.CurrentState.CursorPosition)
            {
                return false;
            }
            int index = this.CurrentState.EditText.IndexOf('.');
            if (index >= 0)
            {
                return (this.formatters[0].MaxDigitsAfterDecimalSeparator == ((this.CurrentState.EditText.Length - index) - 1));
            }
            return ((this.formatters[0].MaxDigitsAfterDecimalSeparator == 0) && (this.formatters[0].MaxDigitsBeforeDecimalSeparator == this.CurrentState.EditText.Length));
        }
    }

    public override bool IsPlainTextLike
    {
        get
        {
            return true;
        }
    }

    private bool IsSignedMask
    {
        get
        {
            return (this.formatters[1] != null);
        }
    }
}



   public class NumericMaskManagerState : MaskManagerCommonState
   {
       // Fields
       private readonly bool fIsNegative;
       private readonly bool fIsNull;
       public static readonly NumericMaskManagerState NullInstance = new NumericMaskManagerState();

       // Methods
       private NumericMaskManagerState()
           : base(string.Empty, 0, 0)
       {
           this.fIsNegative = false;
           this.fIsNull = true;
       }

       public NumericMaskManagerState(string editText, int cursorPosition, int selectionAnchor, bool isNegative)
           : base(editText, cursorPosition, selectionAnchor)
       {
           this.fIsNegative = isNegative;
           this.fIsNull = false;
       }

       public override bool IsSame(MaskManagerState comparedState)
       {
           return ((base.IsSame(comparedState) && (this.IsNegative == ((NumericMaskManagerState)comparedState).IsNegative)) && (this.IsNull == ((NumericMaskManagerState)comparedState).IsNull));
       }

       // Properties
       public bool IsNegative
       {
           get
           {
               return this.fIsNegative;
           }
       }

       public bool IsNull
       {
           get
           {
               return this.fIsNull;
           }
       }
   }


}
